import SandBox from "./sandBox";
import loadHtml, { extract } from "./source";

type CreateAppProps = {
  name: string;
  url: string;
  container: any;
};

type Code = {
  code: string;
  isExternal?: boolean; // 是否是外联js
};

type Source = {
  links: Map<string, Code>;
  scripts: Map<string, Code>;
  htmlDom?: HTMLElement;
};

export default class CreateApp {
  name: string;
  url: string;
  container: any;
  status: "created" | "loading" | "mounted" | "unmount" = "created";
  sandBox;

  source: Source = {
    links: new Map(),
    scripts: new Map(),
  };

  constructor(props: CreateAppProps) {
    this.name = props.name;
    this.url = props.url;
    this.container = props.container; // 自定义组件
    this.sandBox = new SandBox(this.name);

    this.onLoad();
  }

  // 读取资源
  async onLoad() {
    this.status = "loading";
    this.source.htmlDom = await loadHtml(this.url);
    await extract(this); // link -> style -> 隔离, script -> 保存code
    this.mount();
  }

  mount() {
    // 更新自定义组件
    this.updateContainer();
    // 执行js代码
    this.source.scripts.forEach((info) => {
      this.sandBox.run(info.code);
    });

    this.status = "mounted";
  }

  updateContainer() {
    if (!this.source.htmlDom) return;
    const cloneHtml = this.source.htmlDom.cloneNode(true);
    const fragment = document.createDocumentFragment();
    Array.from(cloneHtml.childNodes).forEach((node) => {
      fragment.appendChild(node);
    });
    this.container.appendChild(fragment);
  }

  unmount() {
    this.status = "unmount";
    this.container = null;
  }
}

export const appMap = new Map<string, CreateApp>();
